﻿///<copyright>
/// Copyright © 2009 Stephen Styrchak. All Rights Reserved.
///</copyright>
using System;
using System.ComponentModel;
using Ferpect.ComponentModel.Design;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Media;
#if WINDOWS
using System.ComponentModel.Design;
#endif

namespace Ferpect.ComponentModel.Sprites
{
    [Description("Renders a video as a sprite.")]
#if WINDOWS
    [Designer(Designers.VideoSpriteDesigner, typeof(IDesigner))]
#endif
    public class VideoSprite : Sprite
    {
        private Video video;
        private VideoPlayer player;
        private string videoName;
        private Rectangle? fullScreen;

        private bool looping;
        private bool muted;
        private float volume;

        public VideoSprite()
        {
            this.volume = 1f;
        }

        [Category("Layout")]
        [DefaultValue(false)]
        [RefreshProperties(RefreshProperties.All)]
        public bool FullScreen
        {
            get
            {
                return this.fullScreen.HasValue;
            }
            set
            {
                if (!value)
                {
                    if (this.fullScreen.HasValue)
                    {
                        this.fullScreen = null;
                    }
                }
                else
                {
                    if (!this.fullScreen.HasValue)
                    {
                        this.Position = new Vector2();
                        this.RelativeOrigin = RelativeLocation.TopLeft;
                        this.Origin = new Vector2();
                        this.Scale = 1f;
                    }
                    this.SetFullScreen();
                }
            }
        }

        [Category("Appearance")]
        [TypeConverter(TypeConverters.VideoConverter)]
        [RefreshContent()]
        [RefreshProperties(RefreshProperties.All)]
        public string VideoName
        {
            get
            {
                return this.videoName;
            }
            set
            {
                this.videoName = value;
            }
        }

        [Browsable(false)]
        public Video Video
        {
            get
            {
                return this.video;
            }
        }

        [Category("Behavior")]
        [DefaultValue(1f)]
        public float Volume
        {
            get
            {
                if (this.player != null)
                {
                    return this.player.Volume;
                }
                return this.volume;
            }
            set
            {
                if (this.player != null)
                {
                    this.player.Volume = value;
                }
                this.volume = value;
            }
        }

        [Category("Behavior")]
        [DefaultValue(false)]
        public bool Muted
        {
            get
            {
                if (this.player != null)
                {
                    return this.player.IsMuted;
                }
                return this.muted;
            }
            set
            {
                if (this.player != null)
                {
                    this.player.IsMuted = value;
                }
                this.muted = value;
            }
        }

        [Category("Behavior")]
        [DefaultValue(false)]
        public bool Looping
        {
            get
            {
                if (this.player != null)
                {
                    return this.player.IsLooped;
                }
                return this.looping;
            }
            set
            {
                if (this.player != null)
                {
                    this.player.IsLooped = value;
                }
                this.looping = value;
            }
        }

        [Browsable(false)]
        public MediaState State
        {
            get
            {
                if (this.player != null)
                {
                    return this.player.State;
                }
                return MediaState.Stopped;
            }
        }

        public void Play()
        {
            if (this.player == null)
            {
                throw new InvalidOperationException("LoadContent has not been called.");
            }
            this.player.IsLooped = false;
            this.player.Play(this.video);
        }

        public void PlayLooping()
        {
            if (this.player == null)
            {
                throw new InvalidOperationException("LoadContent has not been called.");
            }
            this.player.IsLooped = true;
            this.player.Play(this.video);
        }

        public void Pause()
        {
            if (this.player == null)
            {
                throw new InvalidOperationException("LoadContent has not been called.");
            }
            this.player.Pause();
        }

        public void Resume()
        {
            if (this.player == null)
            {
                throw new InvalidOperationException("LoadContent has not been called.");
            }
            this.player.Resume();
        }

        public void Stop()
        {
            if (this.player == null)
            {
                throw new InvalidOperationException("LoadContent has not been called.");
            }
            this.player.Stop();
        }

        public override void LoadContent(ContentManager content)
        {
            if (content == null) throw new ArgumentNullException("content");

            if (!String.IsNullOrEmpty(this.videoName))
            {
                this.video = content.Load<Video>(this.videoName);
                this.player = new VideoPlayer();
                this.player.IsLooped = this.looping;
                this.player.IsMuted = this.muted;
                this.player.Volume = this.volume;
            }
            if (this.fullScreen.HasValue)
            {
                this.SetFullScreen();
            }
            this.ResetRelativeOrigin();
        }

        private void SetFullScreen()
        {
            IViewportService viewport = (IViewportService)this.GetService(typeof(IViewportService));
            if (viewport != null)
            {
                if (this.UseTitleSafeArea)
                {
                    this.fullScreen = viewport.TitleSafeArea;
                }
                else
                {
                    this.fullScreen = viewport.ViewportArea;
                }
                return;
            }
            this.fullScreen = new Rectangle();
        }

        public override void UnloadContent()
        {
            if (this.player != null)
            {
                this.player.Dispose();
                this.player = null;
            }
            this.video = null;
        }

        public override void Draw(SpriteBatchStack spriteBatchStack)
        {
            if (spriteBatchStack == null) throw new ArgumentNullException("spriteBatchStack");

            // Only call GetTexture if a video is playing or paused
            if (this.player != null && this.player.State != MediaState.Stopped && this.Visible)
            {
                Texture2D texture = player.GetTexture();

                if (this.fullScreen.HasValue)
                {
                    spriteBatchStack.Current.Draw(texture, this.fullScreen.Value, null, this.Color, 0, Vector2.Zero, this.Effects, this.LayerDepth);
                }
                else
                {
                    spriteBatchStack.Current.Draw(texture, this.Position, null, this.Color, this.Rotation, this.Origin, this.Scale, this.Effects, this.LayerDepth);
                }
            }
        }

        public override Vector2 GetSize()
        {
            if (this.video != null)
            {
                if (this.fullScreen.HasValue)
                {
                    Rectangle sizeRect = this.fullScreen.Value;
                    return new Vector2(sizeRect.Width, sizeRect.Height);
                }
                return new Vector2(this.video.Width, this.video.Height);
            }
            return new Vector2(64, 64);
        }
    }
}
